﻿using Infrastructure.FileOperate;
using Infrastructure.Json;
using SeetaFaceDetectorCLR;
using SeetaFaceRecognizerCLR;
using SeetaPointDetectorCLR;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace VideoNet.Common
{
    public class CZCompare
    {
        FaceDetector FD; PointDetector PD; FaceRecognizer FR;
        string path = "";
        string jsonPath = "";
        public List<CZUserInfo> userInfos = new List<CZUserInfo>();
        const String FD_MODEL = "models/VIPLFaceDetector5.1.2.m9d6.640x480.ats";
        const String PD_MODEL = "models/VIPLPointDetector5.0.pts5.ats";
        // const String FR_MODEL = "models/VIPLFaceRecognizer5.0.RN50.s4.79w.raw.ats";
        const String FR_MODEL = "models/VIPLFaceRecognizer5.0.RN30.light.1N.ats";
        float _rsimilar;
        public CZCompare()
        {
            path = AppDomain.CurrentDomain.BaseDirectory + "CZ/";
            jsonPath = path + "user.json";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            FD = new FaceDetector(FD_MODEL);
            FD.SetMinFaceSize(30);
            PD = new PointDetector(PD_MODEL);
            FR = new FaceRecognizer(FR_MODEL);
            FR.Load(path);
            if (File.Exists(jsonPath))
            {
                string json = FileHelper.ReadFile(jsonPath);
                if (json.Length > 0)
                    userInfos = json.ToList<CZUserInfo>();
            }


        }
        public Rectangle[] FindFace(Bitmap bitmap)
        {
            Rectangle[] faces = FD.Detect(bitmap);
            return faces;
        }
        /// <summary>
        /// 注册
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="dicPath"></param>
        /// <returns></returns>
        public bool Register(CZUserInfo userInfo, string dicPath)
        {
            Bitmap image = new Bitmap(dicPath + userInfo.ImagePath);
            Rectangle[] faces = FD.Detect(image);
            if (faces.Length != 1) return false;
            PointF[] points = PD.Detect(image, faces[0]);
            int index = FR.Register(image, points);
            userInfo.CZIndex = index;
            userInfos.Add(userInfo);
            string json = userInfos.ToJson();
            FileHelper.WriteFile(jsonPath, json);
            return FR.Save(path);
        }
        /// <summary>
        /// 重新加载
        /// </summary>
        public void Reload()
        {
            FR.Load(path);
        }
        /// <summary>
        /// 批量注册
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>

        public bool RegisterBatch(List<CZUserInfo> list)
        {
            foreach (var item in list)
            {
                Bitmap image = new Bitmap(item.ImagePath);
                Rectangle[] faces = FD.Detect(image);
                if (faces.Length != 1) return false;
                PointF[] points = PD.Detect(image, faces[0]);
                item.CZIndex = FR.Register(image, points);
                userInfos.Add(item);
            }
            string json = userInfos.ToJson();
            FileHelper.WriteFile(jsonPath, json);
            return FR.Save(path);
        }
        /// <summary>
        /// 删除用户
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public bool Delete(List<Guid> ids, string dicPath)
        {
            foreach (var item in ids)
            {
                var model = userInfos.FirstOrDefault(c => c.Id == item);
                if (model != null)
                {
                    FR.Delete(model.CZIndex);
                    if (System.IO.File.Exists(dicPath + model.ImagePath))
                    {
                        try
                        {
                            System.IO.File.Delete(dicPath + model.ImagePath);
                        }
                        catch (Exception)
                        {

                        }
                    }
                }
            }
            userInfos.RemoveAll(c => ids.Contains(c.Id));
            string json = userInfos.ToJson();
            FileHelper.WriteFile(jsonPath, json);
            return FR.Save(path);
        }
        /// <summary>
        /// 单人检测
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="face"></param>
        /// <param name="similar"></param>
        /// <returns></returns>
        public CZUserInfo CheckFace(Bitmap bitmap, Rectangle face, out float similar)
        {
            similar = 0;
            PointF[] points = PD.Detect(bitmap, face);
            int max_index = FR.Recognize(bitmap, points, ref similar);
            if (max_index == -1) return null;
            return userInfos[max_index];
        }
        /// <summary>
        /// 多人检测
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="rsimilar"></param>
        /// <returns></returns>
        public List<CZUserInfo> CheckFaces(Bitmap bitmap, float thresSim, ref List<float> similars)
        {
            List<CZUserInfo> list = new List<CZUserInfo>();
            Rectangle[] faces = FindFace(bitmap);
            PointF[] points;
            foreach (var face in faces)
            {
                points = PD.Detect(bitmap, face);
                float[] sims = FR.RecognizeEx(bitmap, points);
                float max = sims.Max();
                if (max > thresSim)
                {
                    int index = Array.IndexOf(sims, sims.Max());
                    list.Add(userInfos[index]);
                    similars.Add(max);
                }
            }
            return list;
        }
        /// <summary>
        /// 多人检测
        /// </summary>
        /// <param name="bitmap"></param>
        /// <param name="rsimilar"></param>
        /// <returns></returns>
        public List<CZUserInfo> CheckFaces(Bitmap bitmap, float similarHour, Rectangle[] faces, ref List<float> similars)
        {
            List<CZUserInfo> list = new List<CZUserInfo>();
            PointF[] points;
            float[] similarArray;
          
            foreach (var face in faces)
            {
                points = PD.Detect(bitmap, face);
                similarArray = FR.RecognizeEx(bitmap, points);
                if (similarArray.Length > 0)
                {
                    float maxSim = 0f;
                    int maxIndex = GetMaxIndex(similarArray, ref maxSim);
                    if (maxSim > similarHour)
                    {
                        list.Add(userInfos[maxIndex]);
                        similars.Add(maxSim);
                    }
                }

            }
          
            return list;
        }
        int GetMaxIndex(float[] array, ref float max)
        {
            int t = 0;
            max = 0f;
            for (int i = 0; i < array.Length; i++)
            {
                if (array[i] > max)
                {
                    t = i;
                    max = array[i];
                }

            }
            return t;

        }




        public void Dispose()
        {
            FD.Dispose();
            PD.Dispose();
            FR.Dispose();
        }

        #region 辅助函数

        #endregion
    }
    public class CZUserInfo
    {
        public Guid Id { get; set; }
        public int CZIndex { get; set; }
        public string ImagePath { get; set; }
        public string Name { get; set; }
        public DateTime FindTime { get; set; }
        public int UserType { get; set; }

    }
}
